/**
 * 
 */
package group.anglers.om.core.custom.sql;

import group.anglers.om.core.exceptions.CustomSQLException;
import group.anglers.om.core.exceptions.OmException;
import group.anglers.om.core.exceptions.UnExpectedException;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author an.pham
 *
 */
public class CustomSQLArchived {
	private static CustomSQLArchived instance;
	
	private Map<String, String> customSqls = null;
	
	private static final String CUSTOM_SQL_ROOT_DIR = "META-INF/custom-sql/";
	private static final String CONFIGURATION_XML_FILE = CUSTOM_SQL_ROOT_DIR + "configuration.xml";
	
	private static final String INCLUDE_ELEMENT = "include";
	private static final String SQL_ELEMENT = "sql";
	
	private static final String FILE_ATTRIBUTE = "file";
	private static final String DBTYPE_ATTRIBUTE = "db-type";
	private static final String ID_ATTRIBUTE = "id";
	
	public static CustomSQLArchived getInstance() throws OmException {
		if(instance == null){
			instance = new CustomSQLArchived();
		}
		return instance;
	}
	
	public String getSql(String id){
		return customSqls.get(id);
	}
	
	private CustomSQLArchived() throws CustomSQLException, UnExpectedException {
		customSqls = new HashMap<String, String>();
		
		try{
			InputStream inputStream = getClass().getClassLoader().getResourceAsStream(CONFIGURATION_XML_FILE);
			
			if(inputStream == null){
				throw new CustomSQLException("Can not found " + CONFIGURATION_XML_FILE + " !!!");
			}

			DocumentBuilder documentBuilder =  DocumentBuilderFactory.newInstance().newDocumentBuilder();

			Document document;
			try {
				document = documentBuilder.parse(inputStream);
			} catch (Exception e) {
				throw new CustomSQLException(e);
			}
			
			Element rootElement = document.getDocumentElement();
			
			String dbType = rootElement.getAttribute(DBTYPE_ATTRIBUTE);
			
			if(dbType == null || dbType.trim().length() == 0){
				throw new CustomSQLException(DBTYPE_ATTRIBUTE + " attribute is required !!!");
			}
			
			NodeList includes = rootElement.getElementsByTagName(INCLUDE_ELEMENT);
			
			Node include = null;
			String includeFile = null;
			
			for(int i=0; i < includes.getLength(); i ++){
				include = includes.item(i);
				
				includeFile = include.getAttributes().getNamedItem(FILE_ATTRIBUTE).getNodeValue();
				
				if(includeFile == null || includeFile.trim().isEmpty()){
					throw new CustomSQLException(FILE_ATTRIBUTE + " attribute is required !!!");
				}
				
				getCustomSqls(documentBuilder, includeFile, dbType);
			}
			
			inputStream.close();
		} catch (CustomSQLException e){
			throw e;
		} catch(Exception e) {
			throw new UnExpectedException(e);
		}
	}
	
	private void getCustomSqls(DocumentBuilder documentBuilder, String includeFile, String dbType) throws OmException {
		try{
			InputStream includeFileStream = null;
			Document includeFileDocument = null;
			NodeList sqlNodes = null;
			Node sqlNode = null;
			String sqlId = null;
			String sqlContent = null;
			
			includeFileStream = getClass().getClassLoader().getResourceAsStream(CUSTOM_SQL_ROOT_DIR + dbType + "/" + includeFile);
			
			if(includeFileStream == null){
				throw new CustomSQLException("Can not found " + CUSTOM_SQL_ROOT_DIR + dbType + "/" + includeFile + " !!!");
			}
			
			try {
				includeFileDocument = documentBuilder.parse(includeFileStream);
			} catch (Exception e) {
				throw new CustomSQLException(e);
			}
			
			sqlNodes = includeFileDocument.getDocumentElement().getElementsByTagName(SQL_ELEMENT);
			
			for(int i=0; i < sqlNodes.getLength(); i ++){
				sqlNode = sqlNodes.item(i);
				
				sqlId = sqlNode.getAttributes().getNamedItem(ID_ATTRIBUTE).getNodeValue();
				
				if(sqlId == null || sqlId.trim().isEmpty()){
					throw new CustomSQLException(ID_ATTRIBUTE + " attribute is required !!!");
				}
				
				sqlContent = sqlNodes.item(i).getTextContent().trim();
				
				if(sqlContent.isEmpty()){
					throw new CustomSQLException("The content of custom sql's ID \"" + sqlId + "\"  is not allowed to empty !!!");
				}
				
				customSqls.put(sqlId, sqlContent);
			}
			
			includeFileStream.close();
		} catch (CustomSQLException e){
			throw e;
		} catch(Exception e) {
			throw new UnExpectedException(e);
		}
	}

}
